#pragma once

#include <algorithm>
#include <functional>
#include <memory>
#include <vector>
#include <mutex>

namespace observer {

template <typename... Args>
class Event;

class Observer {
public:
    struct Base {
        virtual ~Base() = default;
    };

    Observer() = default;
    Observer(Observer&&) = default;

    template <typename T>
    Observer(T&& t) : data(std::make_unique<T>(std::move(t))) {}

    Observer &operator=(const Observer&) = delete;
    Observer &operator=(Observer&&) = default;

    template<typename T>
    Observer& operator=(T&& t) {
        data.reset(std::make_unique<T>(std::move(t)));
        return *this;
    }

    template <typename F, typename... Args>
    void observer(Event<Args...>& event, const F& func) {
        data.reset(new typename Event<Args...>::Observer(event.CreateObserver(func)));
    }

    void reset() { data.reset(); }

    explicit operator bool() const { return bool(data); }

private:
    std::unique_ptr<Base> data;
};

template <typename... Args>
class Event {
public:
    using callback_t = std::function<void(const Args& ...)>;

private:
    using handler_t = size_t;

    struct Handler {
        handler_t id;
        std::shared_ptr<callback_t> callback;
    };

    using handler_list = std::vector<Handler>;

    struct Data {
        handler_t id_counter{0};
        handler_list observers;
        std::mutex list_mutex;
    };

    std::shared_ptr<Data> data;

    handler_t AddHandler(callback_t func) const {
        std::lock_guard<std::mutex> lk(data->list_mutex);
        data->observers.emplace_back(Handler{data->id_counter,
                        std::make_shared<callback_t>(func)});
        return data->id_counter++;
    }

protected:
    Event(const Event&) = default;
    Event& operator=(const Event&) = default;

public:
    class Observer : public observer::Observer::Base {
    private:
        std::weak_ptr<Data> data_;
        handler_t id_{0};

    public:
        Observer() = default;
        Observer(const std::weak_ptr<Data>& data, handler_t id)
                : data_(data), id_(id) {}

        Observer(const Observer&) = delete;
        Observer& operator=(const Observer&) = delete;

        Observer(Observer&&) noexcept = default;
        Observer& operator=(Observer&&) noexcept = default;

        void observe(const Event& event, const callback_t &func) {
            reset();
            *this = event.CreateObserver(func);
        }

        void reset() {
            if (auto obj = data_.lock()) {
                std::lock_guard<std::mutex> lk(obj->list_mutex);
                auto iter = std::find_if(obj->observers.begin(), obj->observers.end(),
                                         [&](const auto& lhs) { return lhs.id == id_; });
                if (iter != obj->observers.end()) {
                    obj->observers.erase(iter);
                }
            }
            data_.reset();
        }

        ~Observer() override { reset(); }
    };

    Event() : data(std::make_shared<Data>()) {}
    Event(Event&& rhs) noexcept : Event() { *this = std::move(rhs); }
    Event& operator=(Event&& rhs) noexcept {
        std::swap(data, rhs.data);
        return *this;
    }

    void NotifyObservers(Args... args) const {
        std::vector<std::weak_ptr<callback_t>> callbacks;
        {
            std::lock_guard<std::mutex> lk(data->list_mutex);
            callbacks.resize(data->observers.size());
            std::transform(data->observers.begin(), data->observers.end(),
                           callbacks.begin(), [](const auto &lhs) { return lhs.callback; });
        }
        for (auto& weak_callback : callbacks) {
            if (auto func = weak_callback.lock()) {
                (*func)(args...);
            }
        }
    }

    // 创建事件关联的观察者
    Observer CreateObserver(const callback_t &func) const {
        return Observer(data, AddHandler(func));
    }

    handler_t Connect(const callback_t &func) const {
        return AddHandler(func);
    }

    void DisConnect(handler_t id) const {
        Observer(data, id).reset();
    }

    void Reset() const {
        std::lock_guard<std::mutex> lk(data->list_mutex);
        data->observers.clear();
    }

    [[nodiscard]] handler_t ObserverCount() const {
        std::lock_guard<std::mutex> lk(data->list_mutex);
        return data->observers.size();
    }
};

}  // namespace observer

